Skip to content

Conversation

@leeleeleeleejun
Copy link
Member

@leeleeleeleejun leeleeleeleejun commented Nov 9, 2025

#️⃣연관된 이슈

📝작업 내용

1. API 응답 형식 변경 대응
백엔드 API의 공통 응답 형식이 data: { data: ... }와 같이 한 단계 더 감싸진 구조로 변경되었습니다.
이에 따라, 데이터를 처리하는 로직 및 관련 타입 정의를 수정했습니다.

2. 지도 페이지(Map) 기능 개선
사용자가 지도를 이동한 후, 해당 위치의 맛집 목록을 새로고침할 수 있는 '현재 위치에서 재검색' 버튼을 UI에 추가했습니다.
맛집 조회 API의 query key에 지도의 bounds (좌표 범위) 값을 포함시켰습니다.
사용자가 '재검색' 버튼을 클릭하면, 현재 지도의 bounds 값이 업데이트되며, 이로 인해 query key가 변경되어 해당 위치의 맛집 데이터를 새로 요청합니다. (지도 이동 시 자동 갱신이 아님)

3. 맛집 등록 결과 페이지 분리
기존에 맛집 등록 '과정'의 마지막 단계(step)로 처리되던 '성공(success)' 및 '실패(fail)' 화면을 독립된 페이지로 분리했습니다.
이유: '등록 과정'과 '등록 결과'는 기능적 성격이 다르다고 판단했습니다.
기대 효과: 페이지 단위로 책임을 분리함으로써 코드의 유지보수성과 확장성을 향상시켰습니다.

스크린샷 (선택)

💬리뷰 요구사항(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 장소 등록 플로우 추가(등록 후 성공/실패 화면으로 분기)
    • 지도에서 현재 범위 기준으로 찾는 새로고침 버튼 추가
    • 가격 표시 개선: 0은 '미등록'으로 표시
  • 버그 수정

    • 사진이 없을 때 배너가 렌더링되지 않도록 수정
  • 개선 사항

    • 캠퍼스 기본값 및 선택 방식 조정
    • 일부 경로 및 데이터 응답 처리 개선으로 안정성 향상

- 등록 성공, 실패 시 페이지 이동 로직 추가
@leeleeleeleejun leeleeleeleejun self-assigned this Nov 9, 2025
@leeleeleeleejun leeleeleeleejun added ✨ Feature 기능 구현 🔨 Refactor 코드 리팩토링 labels Nov 9, 2025
@leeleeleeleejun leeleeleeleejun linked an issue Nov 9, 2025 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Nov 9, 2025

Walkthrough

새로운 장소 생성 뮤테이션 훅과 createNewPlace 서비스가 추가되었고, 쿼리 키(byMap)에 bounds 인수가 도입되었습니다. 캠퍼스 키가 대문자로 변경되고, RefreshButton 컴포넌트와 refresh 아이콘, formatPrice 유틸이 추가되었습니다. 일부 mock 핸들러와 Step 모듈의 re-export가 제거되었고 페이지 컴포넌트들의 export 방식과 스타일이 조정되었습니다.

Changes

Cohort / File(s) 변경 요약
장소 생성 뮤테이션 및 서비스
apps/web/app/_apis/mutations/useCreateNewPlace.ts, apps/web/app/_apis/services/place.ts
useCreateNewPlace 훅 추가 및 createNewPlace API 구현(요청 내 tagIds/categoryIds 숫자 변환, NewPlaceResponse 타입 반환). 서비스 계층에서 응답 래퍼(중첩 data) 처리로 변경됨.
장소 쿼리 및 스키마
apps/web/app/_apis/queries/place.ts, apps/web/app/_apis/schemas/place.ts
PlaceQueryKeys.byMap(bounds)로 쿼리 키에 bounds 포함; schemas에 menuId 추가, photoId를 nullable로 변경, NewPlaceResponse 타입 추가.
API 경로 및 상수
apps/web/app/_constants/path.ts
BY_CATEGORY/BY_MAP 쿼리 문자열 변경, API_PATH.PLACES.NEW.CREATE('/places') 추가, CLIENT_PATH.PLACE_NEW_SUCCESSCLIENT_PATH.PLACE_NEW_FAIL 추가.
캠퍼스 상수 및 스토어 기본값
apps/web/app/_constants/campus.ts, apps/web/app/_store/campus.ts
캠퍼스 키를 singwan/cheonan/yesanSINGWAN/CHEONAN/YESAN로 변경; CampusStore 기본값도 SINGWAN으로 변경.
지도 컴포넌트 및 버튼 리팩토링
apps/web/app/map/MapComponent.tsx, apps/web/app/map/_components/CampusButtom/CampusButtonBox.tsx, apps/web/app/map/_components/CampusButtom/index.tsx
CampusButtonBaxCampusButtonBox로 컴포넌트 및 prop명 변경(onCenterChanged → centerMapToCampus). MapComponent에 갱신 버튼 상태 및 refresh 로직 추가.
지도 UI: RefreshButton 및 Marker 변경
apps/web/app/map/_components/RefreshButton/*, apps/web/app/map/_components/Marker/Marker.tsx
RefreshButton 컴포넌트 추가 및 인덱스 re-export; Marker 클릭 시 이벤트 전파 차단 및 handlePreviewPlace 기본값 추가.
아이콘 시스템 확장
packages/ui/src/components/Icon/IconMap.ts, packages/ui/src/components/Icon/assets/icons/refresh.tsx
refresh 아이콘 컴포넌트 추가 및 iconMap에 등록.
가격 포맷터 도입
apps/web/app/_utils/formatPrice/formatPrice.ts, apps/web/app/_utils/formatPrice/index.ts
formatPrice 유틸 추가(0 → '미등록', 그 외 로케일 포맷) 및 배럴 re-export 추가.
장소 상세 및 메뉴 렌더링
apps/web/app/places/[id]/PlaceDetailPage.tsx, apps/web/app/places/[id]/_components/Menus/Menu.tsx
Banner를 photos.length > 0일 때만 렌더링하도록 조건부 처리; 가격 표시에 formatPrice 사용.
장소 생성 폼 흐름 통합
apps/web/app/places/new/page.tsx, apps/web/app/places/new/_components/Step/PlacePreview/PlacePreview.tsx, apps/web/app/places/new/_components/Step/Category/Category.tsx, 기타 Step 관련 파일
useCreateNewPlace 통합으로 onSubmit이 mutate 호출 사용, Category는 isLoading으로 대체, PlacePreview에 getValues prop 추가. Success/Fail step re-export 제거 및 일부 페이지를 명명된 export → default export로 변경.
페이지 Export 및 스타일 변경
apps/web/app/places/new/success/page.tsx, apps/web/app/places/new/fail/page.tsx, apps/web/app/places/new/_components/Step/Success/index.tsx, apps/web/app/places/new/_components/Step/Fail/index.tsx, apps/web/app/places/new/_components/Step/index.tsx
Success/Fail 모듈의 re-export 제거; Success/Fail 페이지들을 named → default export로 변경하고 일부 패딩/클래스명 조정.
Mock 핸들러 제거/비활성화
apps/web/app/_mocks/handlers/index.ts, apps/web/app/_mocks/handlers/placeHandlers.ts
CategoryHandlers 및 다수의 Place 핸들러를 주석/비활성화(현재는 LIKE.GET만 유지).
응답 래퍼 대응 (서비스 일관화)
apps/web/app/_apis/services/category.ts, apps/web/app/_apis/services/event.ts, apps/web/app/_apis/services/like.ts, apps/web/app/_apis/services/request.ts
axios 응답 구조에 맞춰 2단계(unwrapping)로 data 추출하도록 변경(예: const { data: response } = ...; const { data } = response).
마이너 변화
apps/web/app/map/_components/PreviewPlace/PreviewPlace.tsx
photo key에 fallback으로 displayOrder 사용 (photo.photoId
Next.js 이미지 원격 패턴 확장
apps/web/next.config.ts
remotePatterns에 *.pstatic.net, t1.daumcdn.net(https/http), blog.kakaocdn.net 등을 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PlaceNewPage as Place New Page
    participant PlacePreview
    participant CreateHook as useCreateNewPlace
    participant PlaceService
    participant Router

    User->>PlaceNewPage: 폼 제출
    PlaceNewPage->>PlacePreview: getValues 전달 (미리보기 사용)
    PlacePreview->>PlaceService: byPreview(kakaoPlaceId)
    PlaceService-->>PlacePreview: preview 데이터 반환
    PlaceNewPage->>CreateHook: mutate(formData)
    CreateHook->>PlaceService: createNewPlace(formData)
    PlaceService-->>CreateHook: { status: 'OK' | 'ERROR' }
    alt status === 'OK'
        CreateHook->>Router: navigate CLIENT_PATH.PLACE_NEW_SUCCESS
    else status === 'ERROR'
        CreateHook->>Router: navigate CLIENT_PATH.PLACE_NEW_FAIL
    end
Loading
sequenceDiagram
    participant User
    participant Map as MapComponent
    participant RefreshBtn as RefreshButton
    participant Query as usePlaceQueries.byMap
    participant PlaceService

    User->>Map: 지도 이동/상호작용
    Map->>Map: bounds 계산, showUpdateButton = true
    Map->>RefreshBtn: 렌더링(표시)
    User->>RefreshBtn: 클릭
    RefreshBtn->>Map: handleRefreshClick()
    Map->>Query: 실행 (bounds 인수 포함)
    Query->>PlaceService: GET /places?maxLat=...&maxLng=...
    PlaceService-->>Query: 장소 데이터
    Query-->>Map: 데이터로 지도 업데이트
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

주의가 필요한 영역:

  • apps/web/app/places/new/page.tsx 및 useCreateNewPlace 훅(뮤테이션/네비게이션 실패/성공 경로)
  • 서비스 계층의 응답 래퍼 처리 변경(place.ts, category.ts, event.ts, request.ts, like.ts)
  • PlaceQueryKeys.byMap(bounds) 도입으로 인한 캐시/쿼리 키 영향(queries/place.ts)
  • 캠퍼스 키 대문자 전환에 따른 모든 참조(상수 및 스토어)
  • Mock 핸들러 비활성화가 테스트/로컬 개발에 미치는 영향

Possibly related PRs

Poem

🐰 깡충, 새 길을 만들었네 — 뮤테이션 한 번에 출발!
새 아이콘 반짝, 새 버튼 손짓하며,
가격은 매끄럽게 포맷하고, 지도는 새로고침을 기다려,
대문자 캠퍼스는 폼을 정돈하고,
성공 페이지로 토끼가 깡충 — 축하의 당근 한입! 🎉

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 핵심 변경 사항들(API 응답 형식 수정, 지도 페이지 개선, 결과 페이지 분리)을 포괄적으로 요약하고 있으며, 실제 변경 내용과 일치합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/#54

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@leeleeleeleejun leeleeleeleejun marked this pull request as ready for review November 9, 2025 04:51
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (6)
apps/web/app/_apis/queries/place.ts (1)

20-21: 쿼리 키에 bounds 포함 시 캐시 관리 고려 필요

bounds 객체를 쿼리 키에 직접 포함하면, 지도를 조금씩 이동할 때마다 새로운 캐시 엔트리가 생성될 수 있습니다. 사용자가 지도를 자주 이동하는 경우 메모리에 많은 캐시 엔트리가 누적될 수 있습니다.

다음 개선 방안을 고려해보세요:

  1. bounds 좌표값을 반올림하여 유사한 영역은 같은 캐시 키를 사용
  2. 캐시 크기 제한 설정 (queryClient의 gcTime 조정)

예시:

byMap: (bounds: MapBounds | null) => {
  const roundedBounds = bounds ? {
    minLatitude: Math.floor(bounds.minLatitude * 100) / 100,
    minLongitude: Math.floor(bounds.minLongitude * 100) / 100,
    maxLatitude: Math.ceil(bounds.maxLatitude * 100) / 100,
    maxLongitude: Math.ceil(bounds.maxLongitude * 100) / 100,
  } : null
  return [...PlaceQueryKeys.all(), 'map', roundedBounds] as const
},
apps/web/app/_utils/formatPrice/formatPrice.ts (1)

1-4: 가격 포맷팅 로직 확인

함수가 간결하고 명확합니다. 다만 toLocaleString()에 명시적으로 한국 로케일을 지정하면 더 일관된 결과를 보장할 수 있습니다.

선택적으로 다음과 같이 개선할 수 있습니다:

 export const formatPrice = (price: number): string => {
   if (price === 0) return '미등록'
-  return `${price.toLocaleString()}원`
+  return `${price.toLocaleString('ko-KR')}원`
 }
apps/web/app/_apis/mutations/useCreateNewPlace.ts (2)

11-12: 불필요한 await 제거

mutationFn이 이미 async 함수이므로 내부의 await는 불필요합니다.

-    mutationFn: async (placeData: NewPlaceRequest) =>
-      await createNewPlace(placeData),
+    mutationFn: (placeData: NewPlaceRequest) => createNewPlace(placeData),

20-21: 프로덕션 로깅 개선 권장

console.error는 개발 환경에서는 유용하지만, 프로덕션 환경에서는 적절한 로깅 시스템(예: Sentry, LogRocket 등)을 사용하는 것이 좋습니다.

apps/web/app/_mocks/handlers/placeHandlers.ts (1)

4-39: 주석 처리된 코드 정리

대부분의 mock 핸들러가 주석 처리되어 있습니다. 이 코드들이 더 이상 필요하지 않다면 완전히 제거하는 것이 코드베이스를 깔끔하게 유지하는 데 도움이 됩니다. Git 히스토리를 통해 언제든 이전 코드를 참조할 수 있습니다.

만약 향후 다시 활성화할 계획이라면, 해당 의도를 주석으로 명시하거나 관련 이슈 번호를 남겨두는 것이 좋습니다.

apps/web/app/places/new/page.tsx (1)

37-38: 사용하지 않는 Step 정의 제거

STEP_ORDERSUCCESSFAIL이 정의되어 있지만, 실제로 렌더링되는 <Step> 컴포넌트는 존재하지 않습니다. 이제 useCreateNewPlace 훅에서 내비게이션을 처리하므로 이 정의들을 제거하는 것이 좋습니다.

 export type StepType =
   | 'EVENT_WELCOME'
   | 'CAMPUS'
   | 'PLACE_SEARCH'
   | 'PLACE_PREVIEW'
   | 'RECOMMENDED_MENU'
   | 'DESCRIPTION'
   | 'CATEGORY'
-  | 'SUCCESS'
-  | 'FAIL'

 const STEP_ORDER: Record<StepType, string> = {
   EVENT_WELCOME: 'welcome',
   CAMPUS: '1',
   PLACE_SEARCH: '2',
   PLACE_PREVIEW: '3',
   RECOMMENDED_MENU: '4',
   DESCRIPTION: '5',
   CATEGORY: '6',
-  SUCCESS: 'success',
-  FAIL: 'fail',
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80a5369 and c8562f5.

📒 Files selected for processing (32)
  • apps/web/app/_apis/mutations/useCreateNewPlace.ts (1 hunks)
  • apps/web/app/_apis/queries/place.ts (2 hunks)
  • apps/web/app/_apis/schemas/place.ts (3 hunks)
  • apps/web/app/_apis/services/category.ts (1 hunks)
  • apps/web/app/_apis/services/place.ts (4 hunks)
  • apps/web/app/_constants/campus.ts (1 hunks)
  • apps/web/app/_constants/path.ts (3 hunks)
  • apps/web/app/_mocks/handlers/index.ts (1 hunks)
  • apps/web/app/_mocks/handlers/placeHandlers.ts (1 hunks)
  • apps/web/app/_store/campus.ts (1 hunks)
  • apps/web/app/_utils/formatPrice/formatPrice.ts (1 hunks)
  • apps/web/app/_utils/formatPrice/index.ts (1 hunks)
  • apps/web/app/map/MapComponent.tsx (3 hunks)
  • apps/web/app/map/_components/CampusButtom/CampusButtonBox.tsx (3 hunks)
  • apps/web/app/map/_components/CampusButtom/index.tsx (1 hunks)
  • apps/web/app/map/_components/Marker/Marker.tsx (2 hunks)
  • apps/web/app/map/_components/RefreshButton/RefreshButton.tsx (1 hunks)
  • apps/web/app/map/_components/RefreshButton/index.tsx (1 hunks)
  • apps/web/app/places/[id]/PlaceDetailPage.tsx (1 hunks)
  • apps/web/app/places/[id]/_components/Menus/Menu.tsx (2 hunks)
  • apps/web/app/places/new/_components/Step/Category/Category.tsx (2 hunks)
  • apps/web/app/places/new/_components/Step/Fail/index.tsx (0 hunks)
  • apps/web/app/places/new/_components/Step/PlacePreview/PlacePreview.tsx (1 hunks)
  • apps/web/app/places/new/_components/Step/RecommendedMenu/RecommendedMenu.tsx (2 hunks)
  • apps/web/app/places/new/_components/Step/Success/index.tsx (0 hunks)
  • apps/web/app/places/new/_components/Step/index.tsx (0 hunks)
  • apps/web/app/places/new/fail/page.tsx (2 hunks)
  • apps/web/app/places/new/page.tsx (5 hunks)
  • apps/web/app/places/new/success/page.tsx (2 hunks)
  • apps/web/next.config.ts (1 hunks)
  • packages/ui/src/components/Icon/IconMap.ts (2 hunks)
  • packages/ui/src/components/Icon/assets/icons/refresh.tsx (1 hunks)
💤 Files with no reviewable changes (3)
  • apps/web/app/places/new/_components/Step/index.tsx
  • apps/web/app/places/new/_components/Step/Fail/index.tsx
  • apps/web/app/places/new/_components/Step/Success/index.tsx
🧰 Additional context used
🧬 Code graph analysis (12)
apps/web/app/map/_components/RefreshButton/RefreshButton.tsx (1)
packages/ui/src/utils/cn.ts (1)
  • cn (19-21)
apps/web/app/_apis/mutations/useCreateNewPlace.ts (3)
apps/web/app/_apis/schemas/place.ts (1)
  • NewPlaceRequest (80-80)
apps/web/app/_apis/services/place.ts (1)
  • createNewPlace (105-115)
apps/web/app/_constants/path.ts (1)
  • CLIENT_PATH (45-62)
apps/web/app/places/new/_components/Step/RecommendedMenu/RecommendedMenu.tsx (2)
apps/web/app/_utils/formatPrice/formatPrice.ts (1)
  • formatPrice (1-4)
apps/web/app/_utils/formatPrice/index.ts (1)
  • formatPrice (1-1)
apps/web/app/places/[id]/PlaceDetailPage.tsx (1)
packages/ui/src/components/Banner/Banner.tsx (1)
  • Banner (38-122)
apps/web/app/_apis/services/place.ts (2)
apps/web/app/_constants/path.ts (1)
  • API_PATH (4-43)
apps/web/app/_apis/schemas/place.ts (2)
  • NewPlaceRequest (80-80)
  • NewPlaceResponse (81-83)
apps/web/app/_constants/campus.ts (1)
packages/ui/src/consts/colorVariant.ts (1)
  • COLOR_VARIANTS (1-26)
apps/web/app/places/[id]/_components/Menus/Menu.tsx (2)
apps/web/app/_utils/formatPrice/formatPrice.ts (1)
  • formatPrice (1-4)
apps/web/app/_utils/formatPrice/index.ts (1)
  • formatPrice (1-1)
packages/ui/src/components/Icon/IconMap.ts (1)
packages/ui/src/components/Icon/assets/icons/refresh.tsx (1)
  • Refresh (3-27)
apps/web/app/places/new/page.tsx (2)
apps/web/app/_apis/mutations/useCreateNewPlace.ts (1)
  • useCreateNewPlace (7-25)
apps/web/app/_apis/schemas/place.ts (1)
  • NewPlaceRequest (80-80)
apps/web/app/_apis/queries/place.ts (1)
apps/web/app/_apis/schemas/place.ts (1)
  • MapBounds (69-74)
apps/web/app/map/MapComponent.tsx (2)
apps/web/app/_apis/schemas/place.ts (1)
  • MapBounds (69-74)
apps/web/app/map/_components/CampusButtom/CampusButtonBox.tsx (1)
  • CampusButtonBox (33-57)
apps/web/app/places/new/_components/Step/PlacePreview/PlacePreview.tsx (3)
apps/web/app/_apis/schemas/place.ts (1)
  • NewPlaceRequest (80-80)
apps/web/app/_mocks/data/place.ts (1)
  • PlacePreview (186-222)
apps/web/app/_apis/queries/place.ts (1)
  • usePlaceQueries (27-69)
🔇 Additional comments (40)
apps/web/app/map/_components/Marker/Marker.tsx (1)

55-58: 이벤트 전파 방지 처리 잘 구현됨

마커 클릭 시 stopPropagation()을 호출하여 이벤트 버블링을 방지하는 것은 좋은 개선입니다. 이를 통해 마커 클릭 시 의도하지 않은 지도 클릭 핸들러가 실행되는 것을 방지하고, PR의 목적인 지도 상호작용 개선(재검색 버튼 등)과 잘 맞물립니다.

apps/web/next.config.ts (2)

28-32: LGTM!

blog.kakaocdn.net 패턴이 올바르게 구성되었습니다. HTTPS 프로토콜을 사용하여 보안이 적절히 유지됩니다.


14-17: 원본 리뷰 의견 불일치 - 무시해도 됨

코드베이스에서 실제 pstatic.net 사용 패턴을 확인한 결과, 원본 리뷰 의견은 부정확합니다:

  1. 와일드카드 패턴 (*.pstatic.net)은 필수입니다: 코드베이스에서 search.pstatic.net, pup-review-phinf.pstatic.net, ldb-phinf.pstatic.net 등 여러 서브도메인이 실제로 사용되고 있습니다. 이는 Naver CDN의 표준 구조이며, 와일드카드는 의도적이고 정당한 설정입니다.

  2. port: ''는 불필요하지 않습니다: Next.js 공식 문서에 따르면 port: ''는 유효한 설정이며, 정의되지 않은 포트와는 다른 의미를 갖습니다. 빈 문자열은 "포트 없는 URL만 매칭"을 의미하는 명시적 설정입니다.

현재 코드는 올바르게 구성되어 있습니다.

Likely an incorrect or invalid review comment.

apps/web/app/_constants/campus.ts (3)

10-12: CAMPUS_LOCATION 키가 일관성있게 업데이트되었습니다.

CAMPUS 객체의 키 변경과 동일하게 대문자로 업데이트되어 일관성이 유지됩니다.


16-18: CAMPUS_COLOR 키가 일관성있게 업데이트되었습니다.

CAMPUS 및 CAMPUS_LOCATION과 동일하게 대문자 키로 업데이트되어 전체적인 일관성이 유지됩니다.


4-6: Breaking change 검증 완료 — 변경이 일관되게 적용되었습니다.

코드베이스 전체에서 다음을 확인했습니다:

  • 실행 코드에서 소문자 키 참조 없음: 캠퍼스 키가 singwan/cheonan/yesan에서 SINGWAN/CHEONAN/YESAN으로 완전히 전환됨
  • 주석 처리 코드만 존재: placeHandlers.ts의 주석 처리된 mock 코드(라인 25, 28, 31)에만 소문자 참조가 있으나, 실행되지 않으므로 문제 없음
  • 타입 일관성: 모든 CampusType 사용처에서 새로운 대문자 키로 올바르게 정의되고 사용됨
  • 양쪽 앱 동기화: apps/webapps/admin 모두 대문자로 일관되게 변경됨
apps/web/app/_store/campus.ts (1)

10-10: 기본값이 새로운 대문자 키 형식에 맞게 올바르게 업데이트되었습니다.

apps/web/app/_constants/campus.ts의 변경사항과 일치하도록 기본 캠퍼스 값이 'singwan'에서 'SINGWAN'으로 정확히 업데이트되었습니다. CampusType이 자동으로 새로운 대문자 키를 반영하므로 타입 안정성도 유지됩니다.

packages/ui/src/components/Icon/assets/icons/refresh.tsx (1)

1-27: LGTM! 표준 아이콘 컴포넌트 패턴

Refresh 아이콘 컴포넌트가 올바르게 구현되었습니다. SVG props 타입 지정, 기본 크기 설정, props spread 처리가 적절합니다.

packages/ui/src/components/Icon/IconMap.ts (1)

66-66: LGTM! 아이콘 맵에 refresh 추가

새로운 Refresh 아이콘이 iconMap에 올바르게 추가되었으며, 기존 패턴을 따르고 있습니다.

Also applies to: 137-137

apps/web/app/map/_components/CampusButtom/CampusButtonBox.tsx (1)

16-16: LGTM! 컴포넌트명 오타 수정 및 prop 이름 개선

CampusButtonBaxCampusButtonBox 오타가 수정되었고, onCenterChangedcenterMapToCampus로 prop 이름이 더 명확해졌습니다. 로직 변경 없이 깔끔한 리팩토링입니다.

Also applies to: 33-33, 42-42

apps/web/app/map/_components/RefreshButton/index.tsx (1)

1-1: LGTM! 표준 배럴 export

RefreshButton의 표준 배럴 export 패턴입니다.

apps/web/app/map/_components/CampusButtom/index.tsx (1)

2-2: LGTM! export 업데이트

컴포넌트명 변경에 맞춰 export가 올바르게 업데이트되었습니다.

apps/web/app/map/_components/RefreshButton/RefreshButton.tsx (1)

1-26: LGTM! 깔끔한 RefreshButton 구현

지도 재검색 버튼이 명확하게 구현되었습니다. 절대 위치 지정과 중앙 정렬, refresh 아이콘과 텍스트 조합이 적절합니다.

apps/web/app/map/MapComponent.tsx (3)

27-27: LGTM! 수동 재검색 패턴 구현

지도 이동 시 수동 재검색 패턴이 잘 구현되었습니다. showUpdateButton 상태로 재검색 버튼을 제어하고, 사용자 위치/캠퍼스 중심 이동 시에는 즉시 재검색하는 로직이 명확합니다.

useEffect(refreshMapBounds, [refreshMapBounds])는 map 객체가 초기화된 후 bounds를 설정하는 의도로 보이며, useCallback 의존성과 함께 올바르게 동작합니다.

Also applies to: 37-69, 75-79


83-85: LGTM! RefreshButton 및 CampusButtonBox 통합

RefreshButton의 조건부 렌더링과 CampusButtonBox의 업데이트된 props 전달이 올바르게 구현되었습니다.

Also applies to: 91-91


94-94: 이벤트 전파 처리가 올바르게 구현되어 있습니다.

PlaceMarker 컴포넌트에서 e.pointerEvent.stopPropagation()을 호출하고 있으며, 이는 handlePreviewPlace() 호출 전에 실행됩니다. 따라서 마커 클릭 시 이벤트가 부모 Container로 전파되지 않아 preview 초기화 문제가 발생하지 않습니다.

<Marker
  onClick={(e) => {
    e.pointerEvent.stopPropagation()
    handlePreviewPlace()
  }}
  ...
/>
apps/web/app/places/new/fail/page.tsx (1)

7-34: 변경사항 확인 완료

컴포넌트명 변경 및 기본 내보내기 패턴으로의 전환이 적절합니다. 패딩 추가와 버튼 스타일 변경도 일관성 있게 적용되었습니다.

apps/web/app/_apis/queries/place.ts (1)

46-56: 쿼리 옵션 확인 완료

staleTime: 0enabled: !!bounds 설정이 적절합니다. 재검색 버튼을 통한 수동 갱신 의도와 일치합니다.

apps/web/app/places/new/_components/Step/RecommendedMenu/RecommendedMenu.tsx (2)

4-4: 가격 포맷팅 유틸리티 도입

formatPrice 유틸리티를 사용하여 가격 표시를 일관되게 처리하는 것은 좋은 개선입니다.


71-71: 가격 표시 형식 통일

formatPrice 함수를 통해 가격이 0일 때 "미등록"으로 표시되고, 그 외의 경우 천 단위 구분자와 "원" 기호가 일관되게 적용됩니다.

apps/web/app/_utils/formatPrice/index.ts (1)

1-1: 배럴 익스포트 적절함

formatPrice 유틸리티의 배럴 익스포트가 표준 패턴에 맞게 구현되었습니다.

apps/web/app/places/[id]/_components/Menus/Menu.tsx (2)

1-2: 타입 임포트 최적화 및 유틸리티 추가

PlaceDetail을 타입 전용 임포트로 변경하여 번들 크기를 최적화하고, formatPrice 유틸리티를 추가하여 가격 표시를 일관되게 처리합니다.


24-24: 가격 포맷팅 일관성 개선

formatPrice 함수를 사용하여 다른 컴포넌트들과 동일한 가격 표시 형식을 적용했습니다.

apps/web/app/places/new/_components/Step/Category/Category.tsx (2)

72-75: 제출 버튼으로 변경

버튼 타입이 submit으로 변경되어 폼 제출을 트리거하고, isLoading 상태에 따라 비활성화됩니다. 뮤테이션 기반 플로우와 일관되게 구현되었습니다.


15-18: Props 변경 검증 완료 - 코드 변경 올바름

isSubmittingnextStep props가 제거되고 isLoading이 추가된 변경 사항을 검증했습니다.

확인 사항:

  • Category 컴포넌트에서 새로운 Props 구조(setValue, getValues, isLoading)로 올바르게 마이그레이션됨
  • 부모 페이지에서 isLoading={isSubmitting || isPending}으로 폼 제출 상태와 API 호출 상태를 통합하여 전달
  • 제출 버튼에서 disabled={isLoading}으로 로딩 상태 반영
  • mutate(data) 호출로 뮤테이션 기반 제출 플로우 구현 확인
  • 단계별 네비게이션(nextStep)에서 뮤테이션 기반 제출로의 전환 완료

모든 변경 사항이 일관되게 적용되었으며 폼 제출이 올바르게 처리됩니다.

apps/web/app/places/[id]/PlaceDetailPage.tsx (1)

26-41: 사진이 없을 때 Banner 렌더링 방지

photos.length > 0 조건을 추가하여 사진이 없는 경우 Banner 컴포넌트가 렌더링되지 않도록 개선했습니다. 이는 불필요한 DOM 요소 생성을 방지하고 성능을 최적화합니다.

apps/web/app/_apis/mutations/useCreateNewPlace.ts (1)

8-8: replace vs push 사용 확인

router.replace를 사용하면 브라우저 히스토리에 추가되지 않아 뒤로가기가 불가능합니다. 맛집 등록 후 결과 페이지에서 뒤로가기를 방지하려는 의도라면 적절하지만, UX 관점에서 의도된 동작인지 확인이 필요합니다.

apps/web/app/_apis/schemas/place.ts (2)

12-12: menuId 필드 추가 확인

메뉴 객체에 menuId 필드가 추가되었습니다. 백엔드 API 응답 구조 변경에 맞춰 적절하게 스키마가 업데이트되었습니다.


81-83: 응답 타입 정의 양호

NewPlaceResponse 타입이 명확하게 정의되어 있으며, string literal 타입을 사용하여 타입 안정성을 확보했습니다.

apps/web/app/_apis/services/place.ts (3)

105-115: 응답 처리 일관성 확인 필요

createNewPlace 함수는 다른 API 함수들과 달리 response.data가 아닌 data를 직접 반환하고 있습니다. 다른 함수들은 모두 const { data: response } = await axiosInstance...; const { data } = response 패턴을 사용하는데, 이 함수만 const { data } = await axiosInstance.post(...)를 사용합니다.

백엔드 API가 POST 요청에 대해서는 다른 응답 구조를 사용하는 것이 맞다면 문제없지만, GET과 동일한 래핑 구조를 사용한다면 일관성을 위해 같은 패턴을 적용해야 합니다.

백엔드 API 응답 구조를 확인해주세요:

  • GET 요청: { data: { data: [...] } }
  • POST 요청: { data: { status: ... } } 또는 { status: ... }

24-103: API 응답 래퍼 패턴 적용 확인

모든 GET 요청에서 일관되게 응답 래퍼 패턴(data: responseresponse.data)을 적용했습니다. 백엔드 API 응답 구조 변경에 맞춰 적절하게 업데이트되었습니다.


108-112: 데이터 정규화 로직 양호

tagIdscategoryIds를 숫자 배열로 변환하는 정규화 로직이 적절합니다. 백엔드 API가 숫자 배열을 기대하는 것으로 보이며, 프론트엔드에서 문자열로 관리하던 값을 전송 전에 변환하는 접근이 합리적입니다.

apps/web/app/places/new/_components/Step/PlacePreview/PlacePreview.tsx (1)

16-24: 동적 데이터 조회 개선

하드코딩된 값('1') 대신 getValues().kakaoPlaceId를 사용하여 동적으로 장소 미리보기 데이터를 조회하도록 개선되었습니다. 이는 실제 사용자가 선택한 장소 정보를 가져오는 올바른 구현입니다.

apps/web/app/places/new/success/page.tsx (1)

7-34: 컴포넌트 리팩토링 양호

컴포넌트 이름을 SuccessPage로 변경하고 default export로 전환한 것은 Next.js의 페이지 컴포넌트 규칙과 잘 맞습니다. 패딩 추가와 className 업데이트도 UI 개선에 도움이 됩니다.

apps/web/app/places/new/page.tsx (2)

75-77: 뮤테이션 통합 확인

useCreateNewPlace 훅을 통해 장소 생성 로직이 깔끔하게 분리되었습니다. onSubmit에서 단순히 mutate(data)를 호출하고, 성공/실패 처리는 훅 내부에서 관리하는 구조가 적절합니다.


169-169: 로딩 상태 관리 양호

isSubmittingisPending을 결합하여 폼 검증 중과 API 호출 중 모두 로딩 상태를 표시하는 로직이 적절합니다. 사용자 경험 관점에서 두 단계 모두 대기 상태임을 명확히 전달합니다.

apps/web/app/_constants/path.ts (4)

19-23: 새 장소 생성 엔드포인트 추가가 적절합니다.

CREATE: '/places' 엔드포인트가 RESTful 규칙에 맞게 추가되었으며, NEW 객체 하위에 적절하게 구조화되어 있습니다.


49-50: 등록 결과 페이지 분리가 적절합니다.

성공/실패 결과 페이지를 독립된 경로로 분리하여 등록 과정과 등록 결과의 책임을 명확히 분리한 점이 좋습니다. PR 목표에서 언급한 '페이지 단위 책임 분리' 원칙을 잘 반영하고 있습니다.


7-8: 변경사항이 모두 정상적으로 적용되었습니다.

검증 결과 이전 categoryId= 쿼리 파라미터 형식은 코드베이스에 남아있지 않으며, 서비스 레이어(place.ts line 40)에서 새로운 경로 형식을 올바르게 사용하고 있습니다. 이 breaking change는 모든 호출 지점에서 일관되게 업데이트되었으므로 추가 수정이 필요하지 않습니다.


11-17: 쿼리 파라미터 형식 변경 검증 완료 - 코드 일관성 확인됨

검증 결과, 이전 파라미터 형식(northEastLatitude 등)은 코드베이스에 남아있지 않으며, 모든 BY_MAP 호출처가 새로운 형식으로 올바르게 업데이트되었습니다:

  • path.ts (라인 11-17): 새 형식으로 정의됨 (minLat, maxLat, minLng, maxLng)
  • place.ts (라인 53): 서비스 레이어에서 MapBounds 타입으로 올바르게 전달
  • MapComponent.tsx: MapBounds 타입으로 일관되게 사용
  • schemas/place.ts: MapBounds 타입 정의 및 import 체계 정상

함수 매개변수 이름(minLatitude, maxLatitude 등)은 명확하게 유지되면서 쿼리 스트링은 간결한 형식으로 변환되어 백엔드 API 규격과 일치합니다. 타입 안전성도 전반적으로 유지되고 있습니다.

const photos = z.array(
z.object({
photoId: z.number().transform(String),
photoId: z.nullable(z.number().transform(String)),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

photoId의 nullable 변경 확인 필요

photoId가 nullable로 변경되었습니다. 이는 기존에 photoId를 사용하는 모든 컴포넌트에서 null 케이스를 처리하는지 확인이 필요합니다.

다음 스크립트로 photoId 사용처를 확인하세요:


🏁 Script executed:

#!/bin/bash
# photoId를 사용하는 코드 검색
rg -nP --type=ts --type=tsx -C3 'photoId' -g '!**/node_modules/**' -g '!**/_mocks/**'

Length of output: 27


Now I'll run a corrected script to search for photoId usage:


---

🏁 Script executed:

```shell
#!/bin/bash
# Search for photoId usage in .ts and .tsx files with context
rg -nP 'photoId' -g '*.ts*' -C3 -g '!node_modules/**' -g '!_mocks/**'

Length of output: 11259


이제 PreviewPlace 컴포넌트의 상세 코드를 검토하여 null 처리 여부를 확인하겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# PreviewPlace 컴포넌트의 전체 photos.map 섹션 확인
cat apps/web/app/map/_components/PreviewPlace/PreviewPlace.tsx | head -60 | tail -30

Length of output: 879


PreviewPlace 컴포넌트의 타입 정의와 전체 구조를 확인하겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# PreviewPlace 컴포넌트의 props 타입 및 전체 구조 확인
cat apps/web/app/map/_components/PreviewPlace/PreviewPlace.tsx

Length of output: 2009


이제 place.ts 파일의 PlaceByMap 타입 정의를 확인하겠습니다.


---

🏁 Script executed:

```shell
#!/bin/bash
# place.ts 파일에서 PlaceByMap 타입 정의 확인
cat apps/web/app/_apis/schemas/place.ts

Length of output: 1935


PreviewPlace.tsx에서 nullable photoId 처리 필수

photoId가 nullable로 변경되었으나 PreviewPlace.tsx 40줄에서 React 키로 직접 사용되고 있습니다. photo.photoIdnull이면 React는 유효하지 않은 키 경고를 발생시키고 런타임 오류가 발생합니다.

  • apps/web/app/map/_components/PreviewPlace/PreviewPlace.tsx 40줄: key={photo.photoId} - null 체크 필수
  • apps/admin/src/app/request/[id]/_api/types.ts 4줄: photoId: string 타입도 nullable로 업데이트 필요

null인 사진을 필터링하거나, displayOrder 같은 다른 고유 값을 키로 사용하거나, null 체크 로직을 추가해야 합니다.

🤖 Prompt for AI Agents
In apps/web/app/_apis/schemas/place.ts line 21 and related UI, photoId was
changed to nullable but PreviewPlace.tsx
(apps/web/app/map/_components/PreviewPlace/PreviewPlace.tsx around line 40)
still uses key={photo.photoId} directly and will break when null; update
PreviewPlace to either filter out photos with null photoId before rendering or
use a safe key (e.g. fallback to a stable alternative like displayOrder or a
composite string using index when photoId is null) and add an explicit
null-check when accessing photo.photoId; additionally update
apps/admin/src/app/request/[id]/_api/types.ts (around line 4) to make photoId
nullable (string | null) to match the schema.

Comment on lines 5 to 9
export const getCategories = async (): Promise<Category[]> => {
const { data } = await axiosInstance.get(API_PATH.CATEGORY)
const { data: response } = await axiosInstance.get(API_PATH.CATEGORY)
const { data } = response
return CategorySchema.array().parse(data)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

중첩된 API 응답 구조를 올바르게 처리하고 있습니다.

백엔드 응답 형식 변경에 맞춰 2단계 데이터 추출 로직이 정확하게 구현되었습니다. Zod 스키마를 통한 런타임 검증도 유지되고 있어 타입 안정성이 보장됩니다.

다만, PR 설명에 따르면 이 변경사항이 여러 API 서비스에 영향을 미친다고 하니, 다른 API 서비스 파일들도 동일한 패턴으로 업데이트되었는지 확인해주세요.

다음 스크립트를 실행하여 다른 API 서비스 파일들의 일관성을 확인하세요:


🏁 Script executed:

#!/bin/bash
# Description: 다른 API 서비스 파일들이 동일한 중첩 응답 구조를 처리하는지 확인

# API 서비스 파일들에서 axiosInstance.get/post/put/delete 호출 패턴 검색
echo "=== Checking API service files for response handling pattern ==="
fd -e ts -e tsx --full-path '_apis/services' --exec rg -n -A 3 -B 1 'axiosInstance\.(get|post|put|delete|patch)' {}

echo ""
echo "=== Checking for old pattern (direct data destructuring) ==="
# 이전 패턴 (const { data } = await axiosInstance...)을 직접 사용하는 경우 검색
fd -e ts -e tsx --full-path '_apis/services' --exec rg -n 'const\s*\{\s*data\s*\}\s*=\s*await\s+axiosInstance' {}

Length of output: 3516


API 서비스 파일들 간 응답 처리 패턴이 일관되지 않습니다. 즉각적인 수정이 필요합니다.

검증 결과 일부 함수는 새로운 중첩 응답 구조(데이터 2단계 추출)로 업데이트되었으나, 다른 함수들은 여전히 이전 패턴(직접 데이터 추출)을 사용하고 있습니다. 백엔드 응답 형식이 실제로 변경되었다면, 다음 함수들은 런타임에 실패할 것입니다:

수정 필요 위치:

  • place.ts: addLike (10줄), removeLike (15줄), createNewPlace (113줄)
  • request.ts: getRequests (11줄), getRequestDetail (16줄)
  • event.ts: getEventInfo (11줄), postEventParticipations (19줄), getEventResult (24줄)

이 모든 함수를 category.ts의 getCategories와 동일한 패턴으로 업데이트하세요:

const { data: response } = await axiosInstance.get(...)
const { data } = response
return Schema.parse(data)
🤖 Prompt for AI Agents
In apps/web/app/_apis/services/category.ts around lines 5 to 9, getCategories
currently extracts data twice (const { data: response } = await
axiosInstance.get(...); const { data } = response) and parses via
CategorySchema.array().parse(data); update the other listed API functions to
follow this exact response-unwrapping and parsing pattern: for each call first
destructure as { data: response } = await axiosInstance.<method>(...), then
extract const { data } = response, and finally pass that data into the
appropriate Zod schema's parse method (e.g., Schema.parse(data) or
Schema.array().parse(data) as applicable) for these locations — place.ts
(addLike at line 10, removeLike at 15, createNewPlace at 113), request.ts
(getRequests at 11, getRequestDetail at 16), and event.ts (getEventInfo at 11,
postEventParticipations at 19, getEventResult at 24).

Comment on lines +1 to +8
// import { CategoryHandlers } from './categoryHandlers'
import { PlaceHandlers } from './placeHandlers'
import { EventHandlers } from './eventHandlers'
import { LikeHandlers } from './likeHandlers'
import { RequestHandlers } from './requestHandlers'

export const handlers = [
...CategoryHandlers,
// ...CategoryHandlers,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

CategoryHandlers 비활성화 확인 필요

CategoryHandlers가 주석 처리되어 있습니다. 카테고리 관련 기능이 여전히 정상적으로 작동하는지 확인이 필요합니다.

다음 스크립트로 카테고리 API 사용처를 확인하여 영향 범위를 검증하세요:


🏁 Script executed:

#!/bin/bash
# Description: 카테고리 관련 API 호출 및 의존성 확인

# 카테고리 API 서비스 호출 확인
echo "=== Category API 사용처 확인 ==="
rg -n --type=ts --type=tsx 'from.*@/_apis/services/category' -A 3

# 카테고리 쿼리 훅 사용 확인
echo -e "\n=== Category Query 사용처 확인 ==="
rg -n --type=ts --type=tsx 'useCategoryQueries' -A 2

Length of output: 114


스크립트가 tsx 파일 타입 인식 문제로 실패했습니다. 수정된 명령어로 다시 검증하겠습니다.


🏁 Script executed:

#!/bin/bash
# Description: 카테고리 관련 API 호출 및 의존성 확인 (수정)

# 카테고리 핸들러 사용처 확인
echo "=== CategoryHandlers 사용처 확인 ==="
rg -n 'CategoryHandlers' --type=ts

# 카테고리 API 서비스 호출 확인 (다양한 패턴)
echo -e "\n=== Category API 서비스 사용처 확인 ==="
rg -n 'category' --type=ts -i | grep -E '(import|from|service|api)' | head -20

# categoryHandlers 파일 존재 확인
echo -e "\n=== categoryHandlers 파일 검색 ==="
fd categoryHandlers

# 전체 handlers 파일 내용 확인
echo -e "\n=== handlers 파일 전체 내용 ==="
cat apps/web/app/_mocks/handlers/index.ts

Length of output: 3116


categoryHandlers 파일의 내용과 useCategoryQueries 구현을 확인하여 영향 범위를 정확하게 파악하겠습니다.


🏁 Script executed:

#!/bin/bash
# Description: 카테고리 핸들러와 쿼리 훅 상세 분석

# categoryHandlers.ts 파일 내용 확인
echo "=== categoryHandlers.ts 파일 내용 ==="
cat apps/web/app/_mocks/handlers/categoryHandlers.ts

# useCategoryQueries 구현 확인
echo -e "\n=== useCategoryQueries 훅 구현 확인 ==="
fd category -type f | grep -E '(queries|query)' | head -10

# category 쿼리 파일 찾기
echo -e "\n=== category 쿼리 파일 정확한 위치 ==="
find . -name "*category*" -type f | grep -E '(queries|query)' | grep -v node_modules

# category 쿼리 파일 내용
echo -e "\n=== category 쿼리 구현 ==="
cat apps/web/app/_apis/queries/category.ts 2>/dev/null || cat apps/web/app/_apis/queries/category/index.ts 2>/dev/null || echo "File not found in expected locations"

Length of output: 1135


getCategories 서비스 구현을 확인하여 실제 API 호출 endpoint를 검증하겠습니다.


🏁 Script executed:

#!/bin/bash
# Description: getCategories 서비스 구현 확인

# category 서비스 파일 확인
echo "=== category 서비스 구현 ==="
cat apps/web/app/_apis/services/category.ts 2>/dev/null || echo "File not found"

# API_PATH 상수 확인 (CATEGORY endpoint)
echo -e "\n=== API_PATH.CATEGORY 정의 확인 ==="
rg -n 'CATEGORY' apps/web/app/_constants/path.ts

# 테스트 파일에서 categoryHandlers 사용 여부 확인
echo -e "\n=== 테스트 파일에서 categoryHandlers 사용 여부 ==="
fd -e test.ts -e spec.ts -e test.tsx -e spec.tsx | xargs rg -l 'CategoryHandlers\|category.*handlers\|Category.*mock' 2>/dev/null || echo "테스트 파일에서 CategoryHandlers 직접 사용 없음"

# handlers 등록 파일 자체가 어디서 사용되는지 확인
echo -e "\n=== handlers 파일(index.ts) 사용처 ==="
rg -n 'from.*_mocks/handlers' --type=ts | head -20

Length of output: 687


CategoryHandlers 주석 처리로 인한 카테고리 기능 중단 문제 확인

검증 결과, CategoryHandlers 주석 처리는 실제 문제입니다:

  • getCategories 서비스는 GET /categories 엔드포인트를 호출합니다
  • CategoryHandlers는 정확히 이 엔드포인트를 모킹합니다
  • 5개 컴포넌트(app/page.tsx, places/new/_components/Step/Category/Category.tsx, _components/Categories/Categories.tsx, events/food-slot/page.tsx, categories/[id]/page.tsx)가 useCategoryQueries.list()를 통해 카테고리 데이터를 사용합니다

CategoryHandlers의 주석을 제거하고 활성화하세요:

import { CategoryHandlers } from './categoryHandlers'
...
export const handlers = [
  ...CategoryHandlers,
  ...PlaceHandlers,
  ...EventHandlers,
  ...LikeHandlers,
  ...RequestHandlers,
]
🤖 Prompt for AI Agents
In apps/web/app/_mocks/handlers/index.ts lines 1-8, CategoryHandlers was
commented out which disables the mocked GET /categories endpoint and breaks
components relying on useCategoryQueries.list(); restore and include
CategoryHandlers in the handlers array by uncommenting its import and adding
...CategoryHandlers as the first spread in the exported handlers array so the
categories mock is registered alongside PlaceHandlers, EventHandlers,
LikeHandlers, and RequestHandlers.

Comment on lines +18 to +27
{
protocol: 'https',
hostname: 't1.daumcdn.net',
pathname: '/**',
},
{
protocol: 'http',
hostname: 't1.daumcdn.net',
pathname: '/**',
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

HTTP 프로토콜 사용은 보안 문제를 야기합니다

t1.daumcdn.net에 대해 HTTP와 HTTPS 두 가지 프로토콜을 모두 허용하고 있습니다. HTTP를 통한 이미지 로딩은 다음과 같은 문제를 발생시킵니다:

  • HTTPS 사이트에서 HTTP 리소스를 로드하면 Mixed Content 경고/오류 발생
  • 최신 브라우저는 기본적으로 Mixed Content를 차단
  • 중간자 공격(MITM)에 취약

HTTPS만 사용하도록 수정하는 것을 권장합니다.

다음 diff를 적용하여 HTTP 패턴을 제거하세요:

 {
   protocol: 'https',
   hostname: 't1.daumcdn.net',
   pathname: '/**',
 },
-{
-  protocol: 'http',
-  hostname: 't1.daumcdn.net',
-  pathname: '/**',
-},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
protocol: 'https',
hostname: 't1.daumcdn.net',
pathname: '/**',
},
{
protocol: 'http',
hostname: 't1.daumcdn.net',
pathname: '/**',
},
{
protocol: 'https',
hostname: 't1.daumcdn.net',
pathname: '/**',
},
🤖 Prompt for AI Agents
In apps/web/next.config.ts around lines 18 to 27, the images config currently
allows both 'https' and 'http' for hostname 't1.daumcdn.net'; remove the HTTP
entry so only the HTTPS pattern remains to prevent mixed-content and MITM risks.
Edit the array to delete the block with protocol: 'http', hostname:
't1.daumcdn.net', pathname: '/**' (or change its protocol to 'https' if
deduplication is needed), leaving only the HTTPS object and ensure the final
config is valid JavaScript/TypeScript.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/app/_apis/services/like.ts (1)

9-15: 중첩된 응답 구조를 올바르게 처리했습니다.

좋아요 추가 API에서 새로운 응답 형식을 정확히 반영했습니다. 필요하다면 중간 response 변수에 타입 어노테이션을 추가하여 타입 안정성을 강화할 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8562f5 and 83ba81f.

📒 Files selected for processing (5)
  • apps/web/app/_apis/services/event.ts (1 hunks)
  • apps/web/app/_apis/services/like.ts (1 hunks)
  • apps/web/app/_apis/services/request.ts (1 hunks)
  • apps/web/app/map/_components/Marker/Marker.tsx (2 hunks)
  • apps/web/app/map/_components/PreviewPlace/PreviewPlace.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/map/_components/Marker/Marker.tsx
🧰 Additional context used
🧬 Code graph analysis (3)
apps/web/app/_apis/services/event.ts (1)
apps/web/app/_apis/schemas/event.ts (2)
  • EventSchema (3-14)
  • EventResult (24-24)
apps/web/app/_apis/services/request.ts (2)
apps/web/app/_constants/path.ts (1)
  • API_PATH (4-43)
apps/web/app/_apis/schemas/request.ts (2)
  • RequestSchema (7-13)
  • RequestDetail (23-23)
apps/web/app/_apis/services/like.ts (1)
apps/web/app/_constants/path.ts (1)
  • API_PATH (4-43)
🔇 Additional comments (7)
apps/web/app/map/_components/PreviewPlace/PreviewPlace.tsx (1)

40-40: nullable photoId 처리를 위한 적절한 fallback 추가

photoId가 nullable로 변경됨에 따라 displayOrder를 fallback으로 사용하는 것은 적절한 방어적 코딩입니다.

displayOrder가 항상 정의되어 있고 동일한 장소의 사진 배열 내에서 고유한 값인지 확인해 주세요. React의 key는 안정적이고 고유해야 합니다.

apps/web/app/_apis/services/event.ts (3)

10-14: 중첩된 응답 구조를 올바르게 처리했습니다.

백엔드 API 응답 형식 변경(data: { data: ... })을 정확히 반영한 구현입니다.


16-26: 중첩된 응답 구조를 올바르게 처리했습니다.

POST 요청에서도 두 단계 구조 분해를 일관되게 적용했습니다.


28-32: 중첩된 응답 구조를 올바르게 처리했습니다.

이벤트 결과 조회 API에서도 새로운 응답 형식을 정확히 반영했습니다.

apps/web/app/_apis/services/request.ts (2)

10-14: 중첩된 응답 구조를 올바르게 처리했습니다.

요청 목록 조회에서 새로운 API 응답 형식을 정확히 반영했습니다.


16-22: 중첩된 응답 구조를 올바르게 처리했습니다.

요청 상세 조회에서도 두 단계 구조 분해를 일관되게 적용했습니다.

apps/web/app/_apis/services/like.ts (1)

17-23: 중첩된 응답 구조를 올바르게 처리했습니다.

좋아요 제거 API에서도 두 단계 구조 분해를 일관되게 적용했습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 구현 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] api응답 형식 수정

2 participants